﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using OpenComposite.EII.RepositoryUIs;
using Aga.Controls.Tree;
using OpenComposite.Base.Collections;
using OpenComposite.EII.Repository;
using WeifenLuo.WinFormsUI.Docking;
using OpenComposite.EII.Forms.OrgDesigner;
using OpenComposite.Base;

namespace OpenComposite.EII.RepositoryUIs
{
	public partial class UCOrganisationDesigner : RepositoryItemUI
	{
		#region Initialization
		public UCOrganisationDesigner(IServiceProvider serviceProvider)
			: base(serviceProvider)
		{
			InitializeComponent();
			init();
		}

		private void init()
		{
			this.lvAvailableRoles.ListView.SelectedIndexChanged += new System.EventHandler(this.lvAvailableRoles_SelectedIndexChanged);
			this.lvAvailableRoles.ListView.MouseMove += new MouseEventHandler(lvAvailableRoles_MouseMove);
			this.lvAvailableRoles.ListView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.lvAvailableRoles_MouseUp);
			this.lvAvailableRoles.ListView.DragOver += new DragEventHandler(ucDetails_DragOver);
			this.lvAvailableRoles.Show(dockPanel1, DockState.DockLeft);

			this.tvAdvOrgUnits.TreeView.SelectionChanged += new System.EventHandler(this.tvAdvOrgUnits_SelectionChanged);
			this.tvAdvOrgUnits.TreeView.DragOver += new System.Windows.Forms.DragEventHandler(this.tvAdvOrgUnits_DragOver);
			this.tvAdvOrgUnits.TreeView.MouseClick += new System.Windows.Forms.MouseEventHandler(this.tvAdvOrgUnits_MouseClick);
			this.tvAdvOrgUnits.TreeView.DragDrop += new System.Windows.Forms.DragEventHandler(this.tvAdvOrgUnits_DragDrop);
			this.tvAdvOrgUnits.TreeView.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.tvAdvOrgUnits_ItemDrag);
			this.tvAdvOrgUnits.Show(lvAvailableRoles.Pane, DockAlignment.Top, 0.5);

			this.lvUsers.ListView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.lvUsers_MouseUp);
			this.lvUsers.ListView.SelectedIndexChanged += new System.EventHandler(this.lvUsers_SelectedIndexChanged);
			this.lvUsers.FilterPersons += new StringEventHandler(lvUsers_FilterPersons);
			this.lvUsers.ListView.DragOver += new DragEventHandler(lvUsers_DragOver);
			this.lvUsers.ListView.DragDrop += new DragEventHandler(lvUsers_DragDrop);
			this.lvUsers.Show(dockPanel1, DockState.DockTop);

			this.ucDetails.UserRoles.DragOver += new DragEventHandler(UserRoles_DragOver);
			this.ucDetails.UserRoles.DragDrop += new DragEventHandler(UserRoles_DragDrop);
			this.ucDetails.UserRoles.MouseUp += new MouseEventHandler(UserRoles_MouseUp);
			this.ucDetails.UpdateRole += new EventHandler(ucDetails_UpdateRole);
			this.ucDetails.UpdateOrg += new EventHandler(ucDetails_UpdateOrg);
			this.ucDetails.UpdateUser += new EventHandler(ucDetails_UpdateUser);
			this.ucDetails.UserDetailsShown += new EventHandler(ucDetails_UserDetailsShown);
			this.ucDetails.RoleDetailsShown += new EventHandler(ucDetails_RoleDetailsShown);
			this.ucDetails.OrgDetailsShown += new EventHandler(ucDetails_OrgDetailsShown);
			this.ucDetails.DragOver += new DragEventHandler(ucDetails_DragOver);
			this.ucDetails.Show(dockPanel1, DockState.Document);

			this.lvUsers.Pane.DockWindow.BringToFront();

		}
		#endregion

		private DetailsDock ucDetails = new DetailsDock();
		private AvailableRolesDock lvAvailableRoles = new AvailableRolesDock();
		private UsersDock lvUsers = new UsersDock();
		private OrganisationTree tvAdvOrgUnits = new OrganisationTree();

		public override OpenComposite.EII.Repository.IRepositoryItem RepositoryItem
		{
			get
			{
				save();
				return _org;
			}
			set
			{
				_org = value as Repository.Organization;
				if ( value != null ) load();
			}
		}

		public override string TypeText
		{
			get
			{
				return "Organisation";
			}
		}

		public override string TypeDescription
		{
			get
			{
				return "An Organisation Structure.";
			}
		}

		public override bool CanDelete
		{
			get { return false; }
		}

		#region Private Member

		#region Fields
		private Node _root = new Node();
		private Repository.Organization _org = null;
		#endregion

		#region Methods
		private void save()
		{
			TreeModel model = tvAdvOrgUnits.TreeView.Model as TreeModel;
			if ( model == null ) return;
			OrganisationNode node = model.Root.Nodes[0] as OrganisationNode;
			if ( node == null ) return;
			_org.Save();
			_org = node.Organisation;
			foreach ( ListViewItem item in lvUsers.ListView.Items ) {
				User user = item.Tag as User;
				if ( user == null ) continue;
				user.Save();
			}
		}

		private void load()
		{
			TreeModel model = new TreeModel();
			_root = new OrganisationNode(_org);
			model.Nodes.Add(_root);
			tvAdvOrgUnits.TreeView.Model = model;
			tvAdvOrgUnits.TreeView.SelectedNode = tvAdvOrgUnits.TreeView.FindNodeByTag(_root);

			//foreach ( Node node in model.Nodes ) {
			//    BindingListEx<Person> users = null;
			//    RepositoryItemNode repNode = node as RepositoryItemNode;
			//    if ( repNode.RepositoryItem.RepositoryItemType == ItemType.Organisation ) {
			//        users = Global.Data.GetOrgPersonsByOrg(repNode.RepositoryItem.ID);
			//    }
			//    if ( repNode.RepositoryItem.RepositoryItemType == ItemType.OrgUnit ) {
			//        users = Global.Data.GetOrgPersonsByOrgUnit(repNode.RepositoryItem.ID);
			//    }
			//    foreach ( Person user in users ) {
			//        ListViewItem item = new ListViewItem();
			//        item.Text = user.FormattedName;
			//        item.ImageKey = "user";
			//        item.Tag = user;
			//        lvUsers.ListView.Items.Add(item);
			//    }
			//}
			initAvailableRoles();
		}

		/// <summary>
		/// Displays Users with Last Name starting with the specified filter. Null for all Users (no filter).
		/// </summary>
		/// <param name="filter">The filter.</param>
		private void filterPersons(string filter)
		{
			if ( tvAdvOrgUnits.TreeView.SelectedNode == null ) return;
			BindingListEx<User> users = null;
			lvUsers.ListView.BeginUpdate();
			lvUsers.ListView.Items.Clear();
			try {
				OrganisationNode orgNode = tvAdvOrgUnits.TreeView.SelectedNode.Tag as OrganisationNode;
				if ( orgNode != null ) {
					users = orgNode.Organisation.GetUsers();
				}
				OrganizationalUnitNode orgUnitNode = tvAdvOrgUnits.TreeView.SelectedNode.Tag as OrganizationalUnitNode;
				if ( orgUnitNode != null ) {
					users = orgUnitNode.OrganizationalUnit.GetUsers();
				}
				if ( users != null ) {
					foreach ( User user in users ) {
						if ( filter == null ||
							user.LastName.ToLower().StartsWith(filter) ||
							user.FirstName.ToLower().StartsWith(filter) ) {
							lvUsers.ListView.Items.Add(createPersonItem(user));
						}
					}
				}
			} finally {
				lvUsers.ListView.EndUpdate();
			}

		}

		//private void updateRole()
		//{
		//    if ( lvAvailableRoles.ListView.SelectedItems.Count == 0 ) return;
		//    ListViewItem item = lvAvailableRoles.ListView.SelectedItems[0];
		//    RoleEx role = item.Tag as RoleEx;
		//    role.Name = ucDetails.RoleName;
		//    role.Description = ucDetails.RoleDescription;
		//    role.Save();
		//}

		//private void updateOrg()
		//{
		//    if ( tvAdvOrgUnits.TreeView.SelectedNode == null ) return;
		//    OrganisationNode nodeOrg = tvAdvOrgUnits.TreeView.SelectedNode.Tag as OrganisationNode;
		//    string name = ucDetails.OrganisationName;
		//    string description = ucDetails.OrganisationDescription;
		//    if ( nodeOrg != null ) {
		//        nodeOrg.Organisation.Name = name;
		//        nodeOrg.Organisation.Description = description;
		//        nodeOrg.Organisation.Save();
		//        tvAdvOrgUnits.TreeView.Refresh();
		//    }
		//    OrganizationalUnitNode nodeOrgUnit = tvAdvOrgUnits.TreeView.SelectedNode.Tag as OrganizationalUnitNode;
		//    if ( nodeOrgUnit != null ) {
		//        nodeOrgUnit.OrganizationalUnit.Name = name;
		//        nodeOrgUnit.OrganizationalUnit.Description = description;
		//        nodeOrgUnit.OrganizationalUnit.Save();
		//        tvAdvOrgUnits.TreeView.Refresh();
		//    }
		//}

		private void initAvailableRoles()
		{
			try {
				lvAvailableRoles.ListView.BeginUpdate();
				lvAvailableRoles.ListView.Items.Clear();
				initAvailableRoles(_root as RepositoryItemNode);
			} finally {
				lvAvailableRoles.ListView.EndUpdate();
			}
		}

		private void initAvailableRoles(RepositoryItemNode node)
		{
			if ( node == null ) return;
			BindingListEx<Role> roles = null;
			if ( node.RepositoryItem.RepositoryItemType == ItemType.Organization ) {
				roles = Global.Data.GetOrgRolesByOrg(node.RepositoryItem.ID);
			} else if ( node.RepositoryItem.RepositoryItemType == ItemType.OrgUnit ) {
				roles = Global.Data.GetOrgRolesByOrgUnit(node.RepositoryItem.ID);
			}

			if ( roles != null ) {
				foreach ( Role role in roles ) {
					lvAvailableRoles.ListView.Items.Add(createRoleItem(role));
				}
			}

			foreach ( Node child in node.Nodes ) {
				initAvailableRoles(child as RepositoryItemNode);
			}
		}

		#region ListViewItemHelper
		private ListViewItem createPersonItem(User user)
		{
			ListViewItem newItem = new ListViewItem();
			newItem.Text = user.FormattedName;
			newItem.Name = user.FormattedName;
			newItem.ImageKey = "user";
			newItem.Tag = user;
			return newItem;
		}
	
		private ListViewItem createRoleItem(Role role)
		{
			ListViewItem newItem = new ListViewItem();
			newItem.Text = role.Name;
			newItem.Name = role.Name;
			newItem.ImageKey = "role";
			newItem.Tag = role;
			return newItem;
		}

		private ListViewItem createListViewItem(IRepositoryItem item)
		{
			ListViewItem newItem = new ListViewItem();
			newItem.Text = item.Name;
			newItem.Name = item.Name;
			newItem.ImageKey = item.ImageKey;
			newItem.Tag = item;
			return newItem;
		}
		#endregion

		private void createNewUser()
		{
			// get selected org unit
			OrganizationalUnit orgunit = null;
			if ( tvAdvOrgUnits.TreeView.SelectedNode != null ) {
				OrganizationalUnitNode node = tvAdvOrgUnits.TreeView.SelectedNode.Tag as OrganizationalUnitNode;
				if ( node != null ) {
					orgunit = node.OrganizationalUnit;
				}
			}
			IRepositoryItem item = orgunit;
			// create new user
			User newUser = Global.Data.RepositoryService.GetNewItem<User>(true, ref item);
			if ( newUser == null ) return;	// EXIT

			// set org and orgunit
			if ( item is OrganizationalUnit ) orgunit = (OrganizationalUnit)item;
			if ( orgunit != null ) newUser.OrganizationalUnit = orgunit;
			newUser.Organization = _org;
			newUser.Save();

			// refresh users list
			filterPersons(null);
			//// add user to list view
			//ListViewItem newItem = new ListViewItem();
			//newItem.Text = newUser.FormattedName;
			//newItem.ImageKey = "user";
			//newItem.Tag = newUser;
			//lvUsers.ListView.Items.Add(newItem);
		}

		#endregion

		#region Event Handlers

		#region Filter Links
		private void linkLabelZ_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("z");
		}

		private void linkLabelY_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("y");
		}

		private void linkLabelX_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("x");
		}

		private void linkLabelW_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("w");
		}

		private void linkLabelV_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("v");
		}

		private void linkLabelU_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("u");
		}

		private void linkLabelT_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("t");

		}

		private void linkLabelS_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("s");
		}

		private void linkLabelR_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("r");
		}

		private void linkLabelQ_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("q");
		}

		private void linkLabelP_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("p");
		}

		private void linkLabelO_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("o");
		}

		private void linkLabelN_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("n");
		}

		private void linkLabelM_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("m");
		}

		private void linkLabelL_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("l");
		}

		private void linkLabelK_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("k");
		}

		private void linkLabelJ_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("j");
		}

		private void linkLabelI_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("i");
		}

		private void linkLabelH_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("h");
		}

		private void linkLabelG_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("g");
		}

		private void linkLabelF_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("f");
		}

		private void linkLabelE_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("e");
		}

		private void linkLabelD_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("d");
		}

		private void linkLabelC_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("c");
		}

		private void linkLabelB_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("b");
		}

		private void linkLabelA_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			filterPersons("a");
		}
		#endregion

		#region Context Menu

		#region Organisation Tree Context Menu
		private void addNewOrganisationalUnitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( tvAdvOrgUnits.TreeView.SelectedNode == null ) return;

			Node node = tvAdvOrgUnits.TreeView.SelectedNode.Tag as Node;
			IRepositoryItem item = null;
			OrganizationalUnit newUnit = Global.Data.RepositoryService.GetNewItem<OrganizationalUnit>(true, ref item);
			if ( newUnit == null ) return;
			if ( node is OrganisationNode ) {
				newUnit.Organisation = ( node as OrganisationNode ).Organisation;
			} else if ( node is OrganizationalUnitNode ) {
				newUnit.OrganizationalUnitParent = ( node as OrganizationalUnitNode ).OrganizationalUnit;
			}
			newUnit.Save();
			node.Nodes.Add(new OrganizationalUnitNode(newUnit));
		}
		private void addNewUserToolStripMenuItem_Click(object sender, EventArgs e)
		{
			createNewUser();
		}

		private void deleteOrganisationalUnitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( tvAdvOrgUnits.TreeView.SelectedNode == null ) return;

			OrganizationalUnitNode node = tvAdvOrgUnits.TreeView.SelectedNode.Tag as OrganizationalUnitNode;
			if ( node == null ) return;
			if ( node.OrganizationalUnit.Delete(true) ) {
				node.Parent.Nodes.Remove(node);
				ucDetails.HideDetails();
			}

		}
		#endregion

		#region Available Roles Context Menu
		private void addNewRoleToolStripMenuItem_Click(object sender, EventArgs e)
		{
			IRepositoryItem item = null;
			Role newRole = Global.Data.RepositoryService.GetNewItem<Role>(true, ref item);
			if ( newRole == null ) return;
			newRole.Organisation = _org;
			newRole.IsUnitSpecific = false;
			newRole.Save(); 
			lvAvailableRoles.ListView.Items.Add(createRoleItem(newRole));
		}

		private void removeRoleToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( lvAvailableRoles.ListView.SelectedItems.Count == 0 ) return;
			Role role = lvAvailableRoles.ListView.SelectedItems[0].Tag as Role;
			if ( role == null || role.Delete(true) ) {
				lvAvailableRoles.ListView.Items.Remove(lvAvailableRoles.ListView.SelectedItems[0]);
				ucDetails.HideDetails();
			}
		}
		#endregion

		#region Users Context Menu
		private void addUserToolStripMenuItem_Click(object sender, EventArgs e)
		{
			createNewUser();
		}

		private void removeUserToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( lvUsers.ListView.SelectedItems.Count == 0 ) return;
			User user = lvUsers.ListView.SelectedItems[0].Tag as User;
			if ( user == null || user.Delete(true) ) {
				lvUsers.ListView.Items.Remove(lvUsers.ListView.SelectedItems[0]);
				ucDetails.HideDetails();
			}
		}
		#endregion

		#region Assigned Roles Context Menu

		private void unassignRoleToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( ucDetails.UserRoles.SelectedItems.Count == 0 ) return;
			ucDetails.UserRoles.Items.Remove(ucDetails.UserRoles.SelectedItems[0]);
		}
		#endregion

		private void tvAdvOrgUnits_MouseClick(object sender, MouseEventArgs e)
		{
			if ( e.Button == MouseButtons.Right ) {
				deleteOrganisationalUnitToolStripMenuItem.Visible = true;
				deleteOrganisationalUnitToolStripMenuItem.Enabled = true;
				TreeNodeAdv node = tvAdvOrgUnits.TreeView.GetNodeAt(e.Location);
				if ( node == null ) return;
				OrganisationNode orgNode = node.Tag as OrganisationNode;
				if ( orgNode != null ) {
					//deleteOrganisationalUnitToolStripMenuItem.Visible = false;
					deleteOrganisationalUnitToolStripMenuItem.Enabled = false;
					ctxOrgTree.Show(tvAdvOrgUnits.TreeView, e.Location);
				}
				OrganizationalUnitNode orgUnitNode = node.Tag as OrganizationalUnitNode;
				if ( orgUnitNode != null ) {
					ctxOrgTree.Show(tvAdvOrgUnits.TreeView, e.Location);
				}
			}
		}

		private void lvAvailableRoles_MouseUp(object sender, MouseEventArgs e)
		{
			if ( e.Button == MouseButtons.Right ) {
				addNewRoleToolStripMenuItem.Enabled = true;
				//addNewRoleToolStripMenuItem.Visible = true;
				removeRoleToolStripMenuItem.Enabled = false;
				//removeRoleToolStripMenuItem.Visible = false;
				ListViewItem item = lvAvailableRoles.ListView.GetItemAt(e.X, e.Y);
				if ( item != null ) {
					Role role = item.Tag as Role;
					if ( role != null ) {
						//addNewRoleToolStripMenuItem.Enabled = false;
						//addNewRoleToolStripMenuItem.Visible = false;
						removeRoleToolStripMenuItem.Enabled = true;
						//removeRoleToolStripMenuItem.Visible = true;
					}
				}
				ctxAvailableRoles.Show(lvAvailableRoles.ListView, e.Location);
			}
		}

		private void lvUsers_MouseUp(object sender, MouseEventArgs e)
		{
			if ( e.Button == MouseButtons.Right ) {
				addUserToolStripMenuItem.Enabled = true;
				//addUserToolStripMenuItem.Visible = true;
				removeUserToolStripMenuItem.Enabled = false;
				//removeUserToolStripMenuItem.Visible = false;
				ListViewItem item = lvUsers.ListView.GetItemAt(e.X, e.Y);
				if ( item != null ) {
					User user = item.Tag as User;
					if ( user != null ) {
						//addUserToolStripMenuItem.Enabled = false;
						//addUserToolStripMenuItem.Visible = false;
						removeUserToolStripMenuItem.Enabled = true;
						//removeUserToolStripMenuItem.Visible = true;
					}
				}
				ctxUsers.Show(lvUsers.ListView, e.Location);
			}
		}

		private void UserRoles_MouseUp(object sender, MouseEventArgs e)
		{
			if ( e.Button == MouseButtons.Right ) {
				ListViewItem item = ucDetails.UserRoles.GetItemAt(e.X, e.Y);
				if ( item != null ) {
					Role role = item.Tag as Role;
					if ( role != null ) {
						ctxAssignedRoles.Show(ucDetails.UserRoles, e.Location);
					}
				}
			}
		}

		#endregion

		#region Drag & Drop
		#region tvAdvOrgUnits
		private void tvAdvOrgUnits_DragDrop(object sender, DragEventArgs e)
		{
			if ( e.Effect == DragDropEffects.Move ) {
				TreeNodeAdv[] nodes = e.Data.GetData(typeof(TreeNodeAdv[])) as TreeNodeAdv[];
				if ( nodes == null || nodes.Length == 0 ) return;
				if ( tvAdvOrgUnits.TreeView.DropPosition.Position == NodePosition.Inside ) {
					if ( tvAdvOrgUnits.TreeView.DropPosition.Node.Tag is OrganizationalUnitNode ) {
						if ( tvAdvOrgUnits.TreeView.DropPosition.Node == nodes[0] ) return;
						OrganizationalUnitNode targetNode = tvAdvOrgUnits.TreeView.DropPosition.Node.Tag as OrganizationalUnitNode;
						OrganizationalUnitNode sourceNode = nodes[0].Tag as OrganizationalUnitNode;
						//sourceNode.OrganizationalUnit.Organisation = null;
						sourceNode.OrganizationalUnit.OrganizationalUnitParent = targetNode.OrganizationalUnit;
						sourceNode.OrganizationalUnit.Save();
						sourceNode.Parent = targetNode;
					} else if ( tvAdvOrgUnits.TreeView.DropPosition.Node.Tag is OrganisationNode ) {
						if ( tvAdvOrgUnits.TreeView.DropPosition.Node == nodes[0] ) return;
						OrganisationNode targetNode = tvAdvOrgUnits.TreeView.DropPosition.Node.Tag as OrganisationNode;
						OrganizationalUnitNode sourceNode = nodes[0].Tag as OrganizationalUnitNode;
						sourceNode.OrganizationalUnit.OrganizationalUnitParent = null;
						sourceNode.OrganizationalUnit.Organisation = targetNode.Organisation;
						sourceNode.OrganizationalUnit.Save();
						sourceNode.Parent = targetNode;
					}
				}
			} else if ( e.Effect == DragDropEffects.Link ) {
				ListViewItem item = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
				if ( item == null || item.Tag == null ) return;
				if ( item.Tag is User ) {
					User user = item.Tag as User;
					if ( user == null ) return;
					RepositoryItemNode node = tvAdvOrgUnits.TreeView.DropPosition.Node.Tag as RepositoryItemNode;
					if ( node == null ) return;
					if ( node.RepositoryItem.RepositoryItemType == ItemType.Organization ) {
						user.OrganizationId = node.RepositoryItem.ID;
						user.OrganizationalUnit = null;
					} else if ( node.RepositoryItem.RepositoryItemType == ItemType.OrgUnit ) {
						user.OrganizationUnitId = node.RepositoryItem.ID;
					}
					user.Save();
					//  4 - Shift
					//  8 - Ctrl
					// 32 - Alt
					if ( e.KeyState == 32 ) {
						tvAdvOrgUnits.TreeView.SelectedNode = tvAdvOrgUnits.TreeView.DropPosition.Node;
					}
					ucDetails.ShowUserDetails();
				}
			}
		}

		private void tvAdvOrgUnits_DragOver(object sender, DragEventArgs e)
		{
			if ( e.Data.GetDataPresent(typeof(TreeNodeAdv[])) ) {
				TreeNodeAdv[] nodes = e.Data.GetData(typeof(TreeNodeAdv[])) as TreeNodeAdv[];
				if ( nodes.Length == 0 ) return;
				if ( nodes[0].Tag is OrganizationalUnitNode ) {
					e.Effect = DragDropEffects.Move;
				}
			} else if ( e.Data.GetDataPresent(typeof(ListViewItem)) ) {
				ListViewItem item = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
				if ( item == null || item.Tag == null ) return;
				if ( item.Tag is User ) {
					if ( tvAdvOrgUnits.TreeView.DropPosition.Position == NodePosition.Inside ) {
						e.Effect = DragDropEffects.Link;
					} else {
						e.Effect = DragDropEffects.None;
					}
				}
			}
		}

		private void tvAdvOrgUnits_ItemDrag(object sender, ItemDragEventArgs e)
		{
			tvAdvOrgUnits.TreeView.DoDragDropSelectedNodes(DragDropEffects.Move);
		}
		#endregion

		#region lvUsers
		void lvUsers_DragDrop(object sender, DragEventArgs e)
		{
			ListViewItem item = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
			if ( item == null ) return;
			if ( item.Tag is Role ) {
				Point pt = lvUsers.ListView.PointToClient(new Point(e.X, e.Y));
				ListViewItem target = lvUsers.ListView.GetItemAt(pt.X, pt.Y);
				if ( target == null ) return;
				User user = target.Tag as User;
				if ( user == null ) return;
				user.AddRole(item.Tag as Role);
				user.Save();
			}
		}

		void lvUsers_DragOver(object sender, DragEventArgs e)
		{
			ListViewItem item = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
			if ( item == null ) return;
			if ( item.Tag is Role ) {
				Point pt = lvUsers.ListView.PointToClient(new Point(e.X, e.Y));
				ListViewItem target = lvUsers.ListView.GetItemAt(pt.X, pt.Y);
				if ( target != null && target.Tag is User ) {
					e.Effect = DragDropEffects.Link;
				} else {
					e.Effect = DragDropEffects.None;
				}
			}
		}
		#endregion

		#region ucDetails
		void ucDetails_DragOver(object sender, DragEventArgs e)
		{
			if ( lvUsers.ListView.SelectedItems.Count == 0 ) return;
			ListViewItem item = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
			if ( item == null ) return;
			if ( item.Tag is Role ) {
				ucDetails.ShowUserAssignedRolesTab();
			}
		}

		void UserRoles_DragDrop(object sender, DragEventArgs e)
		{
			ListViewItem item = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
			if ( item == null ) return;
			if ( item.Tag is Role && e.Effect == DragDropEffects.Link ) {
				ucDetails.AddRoleToCurrentUser(item);
			}
		}

		void UserRoles_DragOver(object sender, DragEventArgs e)
		{
			ListViewItem item = e.Data.GetData(typeof(ListViewItem)) as ListViewItem;
			if ( item == null ) return;
			if ( item.Tag is Role ) {
				if ( ucDetails.UserRoles.Items.ContainsKey(item.Name) ) {
					e.Effect = DragDropEffects.None;
				} else {
					e.Effect = DragDropEffects.Link;
				}
			}
		}
		#endregion
		#endregion

		#region Index Changes (Update)
		private void tvAdvOrgUnits_SelectionChanged(object sender, EventArgs e)
		{
			ucDetails.ShowOrgDetails();
			filterPersons(null);
		}

		private void lvUsers_SelectedIndexChanged(object sender, EventArgs e)
		{
			ucDetails.ShowUserDetails();
		}

		private void lvAvailableRoles_SelectedIndexChanged(object sender, EventArgs e)
		{
			ucDetails.ShowRoleDetails();
		}
		#endregion

		private void lvAvailableRoles_MouseMove(object sender, MouseEventArgs e)
		{
			if ( e.Button == MouseButtons.Left ) {
				if ( lvAvailableRoles.ListView.SelectedItems.Count == 0 ) return;
				lvAvailableRoles.ListView.DoDragDrop(lvAvailableRoles.ListView.SelectedItems[0], DragDropEffects.Link);
			}
		}

		private void ucDetails_OrgDetailsShown(object sender, EventArgs e)
		{
			if ( tvAdvOrgUnits.TreeView.SelectedNode == null ) return;
			RepositoryItemNode node = tvAdvOrgUnits.TreeView.SelectedNode.Tag as RepositoryItemNode;
			if ( node != null ) {
				ucDetails.OrganisationName = node.RepositoryItem.Name;
				ucDetails.OrganisationDescription = node.RepositoryItem.Description;
			}
		}

		private void ucDetails_RoleDetailsShown(object sender, EventArgs e)
		{
			if ( lvAvailableRoles.ListView.SelectedItems.Count == 0 ) return;
			Role role = lvAvailableRoles.ListView.SelectedItems[0].Tag as Role;
			ucDetails.RoleName = role.Name;
			ucDetails.RoleDescription = role.Description;
		}

		private void ucDetails_UserDetailsShown(object sender, EventArgs e)
		{
			if ( lvUsers.ListView.SelectedItems.Count == 0 ) return;
			User user = lvUsers.ListView.SelectedItems[0].Tag as User;
			if ( user != null ) {
				ucDetails.DisplayUserData(user);
			}
		}

		private void ucDetails_UpdateUser(object sender, EventArgs e)
		{
			if ( lvUsers.ListView.SelectedItems.Count == 0 ) return;
			User user = lvUsers.ListView.SelectedItems[0].Tag as User;
			ucDetails.SaveUserData(user);
			lvUsers.Refresh(user.ID);
		}

		private void ucDetails_UpdateOrg(object sender, EventArgs e)
		{
			if ( tvAdvOrgUnits.TreeView.SelectedNode == null ) return;
			RepositoryItemNode node = tvAdvOrgUnits.TreeView.SelectedNode.Tag as RepositoryItemNode;
			if ( node == null ) return;
			ucDetails.SaveItemData(node.RepositoryItem);
			//updateOrg();
		}

		private void ucDetails_UpdateRole(object sender, EventArgs e)
		{
			if(lvAvailableRoles.ListView.SelectedItems.Count==0)return;
			Role role = lvAvailableRoles.ListView.SelectedItems[0].Tag as Role;
			ucDetails.SaveRoleData(role);
		}
		
		void lvUsers_FilterPersons(object sender, StringEventArgs e)
		{
			filterPersons(e.StringArg);
		}

		#endregion

		#endregion
	}

	#region class OrganisationNode
	public class OrganisationNode : RepositoryItemNode
	{
		public Repository.Organization Organisation
		{
			get { return RepositoryItem as Organization; }
			set { base.RepositoryItem = value; }
		}

		public OrganisationNode(Repository.Organization org)
			: base(org)
		{
		}

		protected override void OnLoad()
		{
			BindingListEx<OrganizationalUnit> orgUnits = Global.Data.GetOrgUnitsByOrg(base.RepositoryItem.ID);
			foreach ( OrganizationalUnit orgUnit in orgUnits ) {
				this.Nodes.Add(new OrganizationalUnitNode(orgUnit));
			}
		}
	}
	#endregion

	#region class OrganizantionUnitNode
	public class OrganizationalUnitNode : RepositoryItemNode
	{
		public OrganizationalUnit OrganizationalUnit
		{
			get { return base.RepositoryItem as OrganizationalUnit; }
			set { base.RepositoryItem = value; }
		}

		public OrganizationalUnitNode(OrganizationalUnit orgUnit)
			: base(orgUnit)
		{
		}

		protected override void OnLoad()
		{
			BindingListEx<OrganizationalUnit> orgUnits = Global.Data.GetOrgUnitsByOrgUnit(base.RepositoryItem.ID);
			foreach ( OrganizationalUnit orgUnit in orgUnits ) {
				this.Nodes.Add(new OrganizationalUnitNode(orgUnit));
			}
		}
	}
	#endregion

	#region class RoleNode
	public class RoleNode : RepositoryItemNode
	{
		public Role Role
		{
			get
			{
				base.RepositoryItem.Save();
				return base.RepositoryItem as Role;
			}
			set { base.RepositoryItem = value; }
		}
		public RoleNode(Role role)
			:base(role)
		{

		}

		protected override void OnLoad()
		{

		}
	}
	#endregion

	#region class RepositoryItemNode
	public class RepositoryItemNode : Node
	{
		public RepositoryItemNode(IRepositoryItem item)
		{
			_item = item;
			load();
		}

		private void load()
		{
			this.Image = _item.Image;
			OnLoad();
		}

		/// <summary>
		/// Called when node is constructed.
		/// </summary>
		protected virtual void OnLoad() { }

		public sealed override string Text
		{
			get { return _item.Name; }
			set { _item.Name = value; }
		}

		private IRepositoryItem _item = null;

		public IRepositoryItem RepositoryItem
		{
			get { return _item; }
			set { _item = value; }
		}
	}
	#endregion
}